#include "SQLiteDAOFactory.h"

SQLiteDAOFactory* SQLiteDAOFactory::instance = NULL;

SQLiteDAOFactory::SQLiteDAOFactory() {
	database = NULL;
	userDAO = NULL;
	genreDAO = NULL;
	contentDAO = NULL;
	preferenceDAO = NULL;
}

SQLiteDAOFactory::~SQLiteDAOFactory() {
	disconnect_db();
	if (userDAO == NULL)
		delete userDAO;
	if (genreDAO == NULL)
		delete genreDAO;
	if (contentDAO == NULL)
		delete contentDAO;
	if (preferenceDAO == NULL)
		delete preferenceDAO;
}

void SQLiteDAOFactory::create_db() {
	if (database != NULL)
		return;

	if (sqlite3_open(Configuration::get_property("db_name").c_str(), &database)
			!= SQLITE_OK)
		throw SQLiteException(std::string("Cannot create database file: ")
				+ Configuration::get_property("db_name"));

	const char* create_sql[4] = {
	/*Genre table*/
	"CREATE TABLE 'genre' ("
		"'id' INTEGER PRIMARY KEY AUTOINCREMENT,"
		"'name' TEXT"
		")",
	/*Content table*/
	"CREATE TABLE 'content' ("
		"'id' INTEGER PRIMARY KEY AUTOINCREMENT,"
		"'name' TEXT NOT NULL,"
		"'genre_id' INTEGER,"
		"'begin' INTEGER,"
		"'duration' INTEGER"
		")",
	/*User table*/
	"CREATE TABLE 'user' ("
		"'id' INTEGER PRIMARY KEY AUTOINCREMENT,"
		"'device_code' TEXT"
		")",
	/*Preference table*/
	"CREATE TABLE 'preference' ("
		"'id' INTEGER PRIMARY KEY AUTOINCREMENT,"
		"'content_id' INTEGER,"
		"'user_id' INTEGER,"
		"'rating' INTEGER"
		")" };
	sqlite3_stmt* statement;
	std::ostringstream oss;
	int rc;

	rc = sqlite3_prepare_v2(database, create_sql[0], -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		oss << "Error on prepare statement 0. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		oss << "Cannot create table 0. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	rc = sqlite3_prepare_v2(database, create_sql[1], -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		oss << "Error on prepare statement 1. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		oss << "Cannot create table 1. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	rc = sqlite3_prepare_v2(database, create_sql[2], -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		oss << "Error on prepare statement 2. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		oss << "Cannot create table 2. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	rc = sqlite3_prepare_v2(database, create_sql[3], -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		oss << "Error on prepare statement 3. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		oss << "Cannot create table 3. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

void SQLiteDAOFactory::connect_db() {
	if (database != NULL)
		return;

	std::ifstream dbfile(Configuration::get_property("db_name").c_str());
	if (!dbfile.is_open()) {
		Log::verbose("Creating database file");
		create_db();
	} else if (sqlite3_open(Configuration::get_property("db_name").c_str(),
			&database) != SQLITE_OK)
		throw SQLiteException("Cannot connect do database");

	userDAO = new SQLiteUserDAO(database);
	genreDAO = new SQLiteGenreDAO(database);
	contentDAO = new SQLiteContentDAO(database);
	preferenceDAO = new SQLitePreferenceDAO(database);
}

void SQLiteDAOFactory::disconnect_db() {
	if (database != NULL)
		sqlite3_close(database);
}

SQLiteDAOFactory* SQLiteDAOFactory::getInstance() {
	if (instance == NULL)
		instance = new SQLiteDAOFactory();

	return instance;
}

UserDAO* SQLiteDAOFactory::getUserDAO() {
	return userDAO;
}

GenreDAO* SQLiteDAOFactory::getGenreDAO() {
	return genreDAO;
}

ContentDAO* SQLiteDAOFactory::getContentDAO() {
	return contentDAO;
}

PreferenceDAO* SQLiteDAOFactory::getPreferenceDAO() {
	return preferenceDAO;
}
